package cn.ee.dfs.esb.controller;

import cn.ee.dfs.common.annotation.ApiLog;
import cn.ee.dfs.common.annotation.Log;
import cn.ee.dfs.common.entity.DfsResponse;
import cn.ee.dfs.common.entity.LogType;
import cn.ee.dfs.common.exception.DfsException;
import cn.ee.dfs.common.utils.IPUtil;
import cn.ee.dfs.common.utils.NetTool;
import cn.ee.dfs.common.utils.RedisTool;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static cn.ee.dfs.common.utils.DateUtil.distTimeMillisOfDay;

/**
 * Description:
 * Created by TWJ on 2019/8/20 0020 0025 上午 11:13 .
 */
@Slf4j
@RestController
@RequestMapping("api")
public class ApiController //extends BaseController
{
    @Autowired
    RedisTool redisTool;

    @ApiLog(value = "dfs-api-http-get", type = LogType.API)
    @GetMapping(value = "/{systemName}/{serviceName}", produces = MediaType.APPLICATION_JSON_VALUE)
    public DfsResponse apiHttpGet(HttpServletRequest request,
                                  @PathVariable(name = "systemName") String systemName,
                                  @PathVariable(name = "serviceName") String serviceName,
                                  @RequestParam(name = "version") String version,
                                  @RequestParam(name = "queryUri") String queryUri) throws DfsException {
        try {
            String key = request.getHeader("key");
            log.info("-----   apiHttpGet key ----" + key);
            if (!StringUtils.isEmpty(key)) {
                Map<Object, Object> map = redisTool.hmget(key);
                log.info("-- map ->" + map);
                if (map == null || map.size() == 0)
                    return new DfsResponse().code(HttpStatus.NOT_FOUND).message("Not Found");
                String serviceId = (String) map.get("serviceId");
                Integer frequency = (Integer) map.get("frequency");
                Integer dayCall = (Integer) map.get("dayCall");
                String ip = (String) map.get("ip");
                if (dayCall != null && dayCall > frequency) {
                    return new DfsResponse().code(HttpStatus.TOO_MANY_REQUESTS).message("超出频率(" + frequency + "次/天)限制 " + dayCall);
                }
                String ipAddr = IPUtil.getIpAddr(request);
                if (!StringUtils.isEmpty(ip) && !ip.contains(ipAddr))
                    return new DfsResponse().code(HttpStatus.UNAUTHORIZED).message("IP 未获授权 " + ipAddr);
                if (!StringUtils.isEmpty(serviceId)) {
                    redisTool.hincr(key, "dayCall", 1);
//                    String bznsUrl = (String) redisTool.hget(serviceId, "bznsUrl");
                    String esbUrl = (String) redisTool.hget(serviceId, "esbUrl");
                    String queryString = request.getQueryString();
                    Map<Object, Object> hmget = redisTool.hmget(serviceId);

//                    if (StringUtils.isEmpty(esbUrl)) {
//                        return new DfsResponse().code(HttpStatus.BAD_REQUEST).message("esb 地址有误");
//                    }
//                    String path = new StringBuilder(esbUrl).append(queryUri).append("?").append(queryString).toString();
//                    return new DfsResponse().success().data(NetTool.get(path, true));

                    return new DfsResponse().success().data(hmget);

                } else
                    return new DfsResponse().code(HttpStatus.NOT_FOUND).message("Not Found");
            } else
                return new DfsResponse().code(HttpStatus.BAD_REQUEST).message("Bad Request");
//            String queryString = request.getQueryString();
//            String esbPath = svc.getBindEsbPath();
//            String path = new StringBuilder(esbPath).append(queryUri).append("?").append(queryString).toString();
//            log.info("-- path  ->" + path);
//            String s = NetTool.get(path, true);
//            log.info("---- res ->" + s);
//            return new DfsResponse().success().data(test());

        } catch (Exception e) {
            String message = "api 接口调用失败:" + e.getMessage();
            log.error(message, e);
            throw new DfsException(message);
        }
    }

    /**
     * 参数暂时
     */
    @RequestMapping(value = "ws/{systemName}/{serviceName}", produces = MediaType.APPLICATION_JSON_VALUE)
    public Object apiWebService(HttpServletRequest request,
                                @PathVariable(name = "systemName") String systemName,
                                @PathVariable(name = "serviceName") String serviceName,
                                @RequestParam(name = "version") String version) throws DfsException {
        try {
            String key = request.getHeader("key");
            log.info("-----   apiWs key ----" + key);
            if (!StringUtils.isEmpty(key)) {
                Map<Object, Object> map = redisTool.hmget(key);
                log.info("-- map ->" + map);
                if (map == null || map.size() == 0)
                    return new DfsResponse().code(HttpStatus.NOT_FOUND).message("Not Found");
                String serviceId = (String) map.get("serviceId");
                Integer frequency = (Integer) map.get("frequency");
                Integer dayCall = (Integer) map.get("dayCall");
                String ip = (String) map.get("ip");
                if (dayCall != null && dayCall > frequency) {
                    return new DfsResponse().code(HttpStatus.TOO_MANY_REQUESTS).message("超出频率(" + frequency + "次/天)限制 " + dayCall);
                }
                String ipAddr = IPUtil.getIpAddr(request);
                if (!StringUtils.isEmpty(ip) && !ip.contains(ipAddr))
                    return new DfsResponse().code(HttpStatus.UNAUTHORIZED).message("IP 未获授权 " + ipAddr);
                if (!StringUtils.isEmpty(serviceId)) {
                    redisTool.hincr(key, "dayCall", 1);
//                    String bznsUrl = (String) redisTool.hget(serviceId, "bznsUrl");
                    String esbUrl = (String) redisTool.hget(serviceId, "esbUrl");
                    String queryString = request.getQueryString();
                    Map<Object, Object> hmget = redisTool.hmget(serviceId);


//                    String esbPath = svc.getBindEsbPath();
//                    String namespace = svc.getNamespace();
//                    String nameSpace = "http://eastelite.com.cn/webservices/";
//                    String wsParam = generateWsParam(serviceName, nameSpace, request.getParameterMap());
//                    lg.info("  wsParam :" + wsParam);
////
//                    return NetTool.postXmlParams("http://192.168.1.111:8003/ws/ws1", wsParam);

                    return new DfsResponse().success().data(hmget);
//                    return new DfsResponse().success().data(NetTool.get(path, true));
                } else
                    return new DfsResponse().code(HttpStatus.NOT_FOUND).message("Not Found");
            } else
                return new DfsResponse().code(HttpStatus.BAD_REQUEST).message("Bad Request");
//            String queryString = request.getQueryString();
//            String esbPath = svc.getBindEsbPath();
//            String path = new StringBuilder(esbPath).append(queryUri).append("?").append(queryString).toString();
//            log.info("-- path  ->" + path);
//            String s = NetTool.get(path, true);
//            log.info("---- res ->" + s);
//            return new DfsResponse().success().data(test());

        } catch (Exception e) {
            String message = "api 接口调用失败:" + e.getMessage();
            log.error(message, e);
            throw new DfsException(message);
        }
    }

    /**
     * 根据wsdl mule配置项生成  http post raw 请求  like this:
     * <?xml version='1.0' encoding='UTF-8'?>
     * <ns0:GetClassNameList xmlns:ns0="http://eastelite.com.cn/webservices/">
     * <ns0:rootCode>6101051006</ns0:rootCode>
     * ...
     * </ns0:GetClassNameList>
     */
    private String generateWsParam(String serviceName, String nameSpace, Map<String, String[]> params) {
        StringBuilder xml = new StringBuilder("<?xml version='1.0' encoding='UTF-8'?>");
        xml.append("<ns0:").append(serviceName).append(" xmlns:ns0=\"").append(nameSpace).append("\">");
        params.forEach((k, v) -> xml.append("<ns0:").append(k).append(">").append(v[0]).append("</ns0:").append(k).append(">"));
        xml.append("</ns0:").append(serviceName).append(">");
        return xml.toString();
    }


    /**
     * apiTestWebservice
     */
    @RequestMapping(value = "test/ws/json/{serviceName}", produces = MediaType.APPLICATION_JSON_VALUE)
    public Object apiTestWebservice(HttpServletRequest request,
                                    @PathVariable(name = "serviceName") String serviceName
                                    ) {
        String nameSpace = "http://eastelite.com.cn/webservices/";
        String url = "http://127.0.0.1:8003/ws/ws1";
        String wsParam = generateWsParam(serviceName, nameSpace, request.getParameterMap());
        log.info("  nameSpace :" + nameSpace);
        log.info("  url :" + url);
        log.info("  wsParam :" + wsParam);
//
        return NetTool.postXmlParams(url, wsParam);
    }
      @RequestMapping(value = "test/ws/xml/{serviceName}", produces = MediaType.APPLICATION_JSON_VALUE)
    public Object apiTestWebserviceJson(HttpServletRequest request,
                                    @PathVariable(name = "serviceName") String serviceName
                                    ) {
        String nameSpace = "http://eastelite.com.cn/webservices/";
        String url = "http://127.0.0.1:8003/ws/ws2";
        String wsParam = generateWsParam(serviceName, nameSpace, request.getParameterMap());
//        log.info("  nameSpace :" + nameSpace);
//        log.info("  url :" + url);
//        log.info("  wsParam :" + wsParam);
//
        return NetTool.postXmlParams(url, wsParam);
    }






    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    Object test() {
        redisTemplate.opsForHash().put("hashValue", "map1", "map1-1");
        redisTemplate.opsForHash().put("hashValue", "map2", "map2-2");
        Map<Object, Object> map1 = redisTemplate.opsForHash().entries("hashValue");
        System.out.println("通过entries(H key)方法获取变量中的键值对:" + map1);
        List<Object> hashList = redisTemplate.opsForHash().values("hashValue");
        log.info("通过values(H key)方法获取变量中的hashMap值:" + hashList);
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("mapk1","mapv1");
//        redisTool.hmset("key", map);
//        Map<Object, Object> key = redisTool.hmget("key");

        Map newMap = new HashMap();
        newMap.put("map3", "map3-3");
        newMap.put("map5", "map5-5");
        redisTemplate.opsForHash().putAll("hashValue", newMap);
        Map<Object, Object> hashValue = redisTemplate.opsForHash().entries("hashValue");
        System.out.println("通过putAll(H key, Map<? extends HK,? extends HV> m)方法以map集合的形式添加键值对:" + hashValue);

        redisTemplate.opsForHash().delete("hashValue", "map1", "map2");
        Map<Object, Object> hashValue1 = redisTemplate.opsForHash().entries("hashValue");
        System.out.println("通过delete(H key, Object... hashKeys)方法删除变量中的键值对后剩余的:" + hashValue1);

        Object mapValue = redisTemplate.opsForHash().get("hashValue", "map3");
        System.out.println("通过get(H key, Object hashKey)方法获取map键的值:" + mapValue);

//匹配获取键值对，ScanOptions.NONE为获取全部键对，ScanOptions.scanOptions().match("map1").build()
// 匹配获取键位map1的键值对,不能模糊匹配。
//        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan("hashValue", ScanOptions.scanOptions().match("map1").build());
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan("hashValue", ScanOptions.NONE);
        while (cursor.hasNext()) {
            Map.Entry<Object, Object> entry = cursor.next();
            System.out.println("通过scan(H key, ScanOptions options)方法获取匹配键值对:" + entry.getKey() + "---->" + entry.getValue());
        }
        redisTemplate.opsForHash().putIfAbsent("hashValue", "map6", "map6-6");
        Map<Object, Object> hashValue2 = redisTemplate.opsForHash().entries("hashValue");
        System.out.println("通过putIfAbsent(H key, HK hashKey, HV value)方法添加不存在于变量中的键值对:" + hashValue2);

        long hashLength = redisTemplate.opsForHash().size("hashValue");
        System.out.println("通过size(H key)方法获取变量的长度:" + hashLength);

        Set<Object> keySet = redisTemplate.opsForHash().keys("hashValue");
        System.out.println("通过keys(H key)方法获取变量中的键:" + keySet);
        Object mapValue5 = redisTemplate.opsForHash().get("hashValue", "map5");
        System.out.println("通过get(H key, Object hashKey)方法获取map键的值:" + mapValue5);

        return hashValue2;
//        return hashValue1;
//        return hashValue;
//        return mapValue;
//        return hashList;
//        return key;
    }


    @GetMapping("test/{index}")
    public Object t(@PathVariable("index") String index) {
        switch (index) {
            case "1":
                test1();
                break;
            case "2":
                test2();
                break;
            case "3":
                test3();
                break;
            case "4":
                test4();
                break;
            case "5":
                test5();
                break;
            case "6":
                test6();
                break;
            case "7":
                test7();
                break;
            case "8":
                test8();
                break;
            case "9":
                test9();
                break;
            case "10":
                test10();
                break;
        }

        return null;
    }


    public void test1() {
        //向集合中插入元素，并设置分数
        redisTemplate.opsForZSet().add("ranking-list", "p1", 2.1);

        //向集合中插入多个元素
        DefaultTypedTuple<String> tuple1 = new DefaultTypedTuple<String>("p2", 1.1);
        DefaultTypedTuple<String> tuple2 = new DefaultTypedTuple<String>("p3", 3.1);
        redisTemplate.opsForZSet().add("ranking-list", new HashSet<>(Arrays.asList(tuple1, tuple2)));

        //打印
        printZSet("ranking-list");
    }

    public void test2() {
        printZSet("ranking-list");
        //从集合中删除指定元素
        redisTemplate.opsForZSet().remove("ranking-list", "p1");
        printZSet("ranking-list");
    }

    public void test3() {
        //为指定元素加分
        Double score = redisTemplate.opsForZSet().incrementScore("ranking-list", "p1", 2);
        System.out.println(score);//返回加分后的得分
        printZSet("ranking-list");
    }

    public void test4() {
        //返回指定成员的排名（从小到大）
        Long rank = redisTemplate.opsForZSet().rank("ranking-list", "p1");
        //从大到小
        Long reverseRank = redisTemplate.opsForZSet().reverseRank("ranking-list", "p1");
        System.out.println(rank);
        System.out.println(reverseRank);
    }

    public void test5() {
        //返回集合内元素的排名，以及分数（从小到大）
        Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().rangeWithScores("ranking-list", 0, -1);
        for (ZSetOperations.TypedTuple<String> tuple : tuples) {
            System.out.println(tuple.getValue() + " : " + tuple.getScore());
        }
    }

    public void test6() {
        //返回集合内元素在指定分数范围内的排名（从小到大）
        Set<String> ranking = redisTemplate.opsForZSet().rangeByScore("ranking-list", 0, 5);
        System.out.println(ranking);
        //带偏移量和个数，下例意为从第二个开始，要三个
        Set<String> ranking2 = redisTemplate.opsForZSet().rangeByScore("ranking-list", 0, 5, 1, 3);
        System.out.println(ranking2);
        //也可以带分数返回，类似于test5
    }

    public void test7() {
        //返回集合内指定分数范围的成员个数
        Long count = redisTemplate.opsForZSet().count("ranking-list", 0, 2);
        System.out.println(count);
        //返回集合内的成员个数
        Long size = redisTemplate.opsForZSet().size("ranking-list");//等同于zCard(key);
        System.out.println(size);
    }

    public void test8() {
        //获得指定元素的分数
        Double score = redisTemplate.opsForZSet().score("ranking-list", "p1");
        System.out.println(score);
    }

    public void test9() {
        //删除指定索引范围的元素
        printZSet("ranking-list");
        redisTemplate.opsForZSet().removeRange("ranking-list", 0, 0);
        printZSet("ranking-list");
    }

    public void test10() {
        //删除指定分数范围内的元素
        printZSet("ranking-list");
        redisTemplate.opsForZSet().removeRangeByScore("ranking-list", 4, 5);
        printZSet("ranking-list");
        redisTemplate.opsForZSet();
    }

    //求交集并集与set类似
    private void printZSet(String key) {
        //按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部
        Set<String> range = redisTemplate.opsForZSet().range(key, 0, -1);
        //reverseRange 从大到小
        System.out.println(range);
    }


}
